package com.jinke.api.modules.app.util;

import java.io.ByteArrayInputStream;
import java.util.Base64;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.ServiceException;
import com.aliyun.oss.model.ObjectMetadata;
import com.aliyun.oss.model.PutObjectRequest;
import com.aliyun.oss.model.PutObjectResult;
import com.jinke.api.modules.app.config.OssConfig;
import com.jinke.api.modules.base.constant.FileConstant;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.Date;
import java.util.UUID;

@Data
@Component
@Slf4j
public class OssUtil {

    @Autowired
    private OssConfig cfg;

    public String upload(MultipartFile file) {
        return upload("system", file);
    }
    public String uploadHead(MultipartFile file) {
        return upload("head", file);
    }

    /**
     * 上传文件
     *
     * @param file
     * @return
     */
    public String upload(String prefix, MultipartFile file) {
        if (file.isEmpty()) {
            throw new ServiceException("上传文件不能为空");
        }
        if (!checkFileSize(file.getSize(), FileConstant.LEN, FileConstant.UNIT_M)) {
            throw new ServiceException("上传文件大小不能超过10M");
        }
        // 创建OSSClient实例。
        OSS ossClient = new OSSClientBuilder().build(cfg.getEndpoint(), cfg.getAccessKey(), cfg.getAccessKeySecret());
        // 上传文件流。
        // 保存路径，注意：这里不要以 / 或 \ 开头
        String path = prefix + "/" + new SimpleDateFormat("yyyyMMdd").format(new Date());
        String originalFilename = file.getOriginalFilename();
        String fileName = path + "/" + UUID.randomUUID().toString().replace("-", "") + originalFilename.substring(originalFilename.lastIndexOf("."));
        try {
            ossClient.putObject(cfg.getBucket(), fileName, file.getInputStream());
        } catch (IOException e) {
            throw new ServiceException("上传失败" + e.getMessage());
        }
        // 关闭OSSClient。
        ossClient.shutdown();
        return cfg.getCdn() + "/" + fileName;
    }

    public String upload(String prefix, String fileName, String url) {
        if (url==""){
            log.info("上传地址为空");
            return "";
        }

        // 创建OSSClient实例。
        OSS ossClient = new OSSClientBuilder().build(cfg.getEndpoint(), cfg.getAccessKey(), cfg.getAccessKeySecret());
        // 上传文件流。
        // 保存路径，注意：这里不要以 / 或 \ 开头
        String path = prefix + "/" + fileName;
        int retryCount = 0;
        while (retryCount < 10) {
            try {
                InputStream inputStream = null;
                URL url1 = new URL(url);
                if ("true".equals(System.getenv("local"))) {
                    Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress("localhost", 7890));
                    HttpURLConnection connection = (HttpURLConnection) url1.openConnection(proxy);
                    inputStream = connection.getInputStream();
                } else {
                    inputStream = url1.openStream();
                }

                // 创建PutObjectRequest对象。
                PutObjectRequest putObjectRequest = new PutObjectRequest(cfg.getBucket(), path, inputStream);
                // 创建PutObject请求。
                PutObjectResult result = ossClient.putObject(putObjectRequest);
                // 关闭输入流。
                inputStream.close();
                return cfg.getCdn() + "/" +prefix+"/"+ fileName;
            } catch (IOException e) {
                e.printStackTrace();
                try {
                    Thread.sleep(1000);
                    log.error("文件上传失败 重试 {}",url);
                } catch (InterruptedException ex) {
                    throw new RuntimeException(ex);
                }
                retryCount++;
            }
        }
        ossClient.shutdown();
        return cfg.getCdn() + "/" +prefix+"/"+ fileName;
    }

    /**
     * 延迟单
     * @param prefix
     * @param fileName
     * @param url
     * @return
     */
    public String uploadforYCD(String prefix, String fileName, String url) {

        // 创建OSSClient实例。
        OSS ossClient = new OSSClientBuilder().build(cfg.getEndpoint(), cfg.getAccessKey(), cfg.getAccessKeySecret());
        // 上传文件流。
        // 保存路径，注意：这里不要以 / 或 \ 开头
        String path = prefix + "/" + fileName;
        try {
            InputStream inputStream = null;
            URL url1 = new URL(url);
            if ("true".equals(System.getenv("local"))) {
                Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress("localhost", 7890));
                HttpURLConnection connection = (HttpURLConnection) url1.openConnection(proxy);
                inputStream = connection.getInputStream();
            } else {
                inputStream = url1.openStream();
            }

            // 创建PutObjectRequest对象。
            PutObjectRequest putObjectRequest = new PutObjectRequest(cfg.getBucket(), path, inputStream);
            // 创建PutObject请求。
            PutObjectResult result = ossClient.putObject(putObjectRequest);
            // 关闭输入流。
            inputStream.close();
            return cfg.getCdn() + "/" + fileName;
        } catch (IOException e) {
            log.error("文件上传失败 重试 {}-{}",url,e.getMessage());
            return "";
        }
    }



    public String uploadLocal(String prefix, String fileName, String localFilePath) {

        // 创建OSSClient实例。
        OSS ossClient = new OSSClientBuilder().build(cfg.getEndpoint(), cfg.getAccessKey(), cfg.getAccessKeySecret());
        // 上传文件流。
        // 保存路径，注意：这里不要以 / 或 \ 开头
        String path = prefix + "/" + fileName;
        try {
            InputStream inputStream = new FileInputStream(localFilePath);

            // 创建PutObjectRequest对象。
            PutObjectRequest putObjectRequest = new PutObjectRequest(cfg.getBucket(), path, inputStream);
            // 创建PutObject请求。
            PutObjectResult result = ossClient.putObject(putObjectRequest);
//        String originalFilename = file.getOriginalFilename();
//        String fileName = path + "/" + UUID.randomUUID().toString().replace("-", "") + originalFilename.substring(originalFilename.lastIndexOf("."));
//
//            ossClient.putObject(cfg.getBucket(), fileName, file.getInputStream());
        } catch (IOException e) {
            throw new ServiceException("上传失败" + e.getMessage());
        }
        // 关闭OSSClient。
        ossClient.shutdown();
        return cfg.getCdn() + "/" + fileName;
    }
    public static Date toDate(LocalDateTime localDateTime) {
        return Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant());
    }
    public String uploadWithExpiration(String prefix, String fileName, File file) {

        // 创建OSSClient实例。
        OSS ossClient = new OSSClientBuilder().build(cfg.getEndpoint(), cfg.getAccessKey(), cfg.getAccessKeySecret());
        // 上传文件流。
        // 保存路径，注意：这里不要以 / 或 \ 开头
        String path = prefix + "/" + fileName;
        try {
            InputStream inputStream = new FileInputStream(file);
            ObjectMetadata metadata = new ObjectMetadata();
            metadata.setExpirationTime(toDate(LocalDateTime.now().plusHours(1))); // 设置过期时间为 2024 年 12 月 31 日 23:59:59

            // 创建PutObjectRequest对象。
            PutObjectRequest putObjectRequest = new PutObjectRequest(cfg.getBucket(), path, inputStream,metadata);
            // 创建PutObject请求。
            PutObjectResult result = ossClient.putObject(putObjectRequest);
//        String originalFilename = file.getOriginalFilename();
//        String fileName = path + "/" + UUID.randomUUID().toString().replace("-", "") + originalFilename.substring(originalFilename.lastIndexOf("."));
//
//            ossClient.putObject(cfg.getBucket(), fileName, file.getInputStream());
        } catch (IOException e) {
            throw new ServiceException("上传失败" + e.getMessage());
        }
        // 关闭OSSClient。
        ossClient.shutdown();
        return cfg.getCdn() + "/" + fileName;
    }


    public String uploadBase64(String prefix, String objectId,String base64EncodedData) {
        if (base64EncodedData == null || base64EncodedData.isEmpty()) {
            throw new ServiceException("Base64 数据不能为空");
        }

        // 将 base64 编码转换为字节数组
        byte[] data = Base64.getDecoder().decode(base64EncodedData);

        // 创建 OSSClient 实例
        OSS ossClient = new OSSClientBuilder().build(cfg.getEndpoint(), cfg.getAccessKey(), cfg.getAccessKeySecret());

        // 上传文件流
        // 保存路径，注意：这里不要以 / 或 \ 开头
        String fileName = prefix + "/" + objectId+".pdf";

        try (ByteArrayInputStream inputStream = new ByteArrayInputStream(data)) {
            ossClient.putObject(cfg.getBucket(), fileName, inputStream);
        } catch (IOException e) {
            throw new ServiceException("上传失败" + e.getMessage());
        }

        // 关闭 OSSClient
        ossClient.shutdown();

        return cfg.getCdn() + "/" + fileName;
    }

    /**
     * 删除文件
     *
     * @param url
     */
    public void remove(String url) {
        for (int i = 0; i < 3; i++) {
            url = url.substring(url.indexOf("/") + 1);
        }
        // 创建OSSClient实例。
        OSS ossClient = new OSSClientBuilder().build(cfg.getEndpoint(), cfg.getAccessKey(), cfg.getAccessKeySecret());
        // 删除操作
        ossClient.deleteObject(cfg.getBucket(), url);
        // 关闭OSSClient。
        ossClient.shutdown();
    }

    /**
     * 校验文件
     *
     * @param len
     * @param size
     * @param unit
     * @return
     */
    public boolean checkFileSize(Long len, int size, String unit) {
        double fileSize = 0;
        if (FileConstant.UNIT_B.equals(unit.toUpperCase())) {
            fileSize = (double) len;
        } else if (FileConstant.UNIT_K.equals(unit.toUpperCase())) {
            fileSize = (double) len / 1024;
        } else if (FileConstant.UNIT_M.equals(unit.toUpperCase())) {
            fileSize = (double) len / 1048576;
        } else if (FileConstant.UNIT_G.equals(unit.toUpperCase())) {
            fileSize = (double) len / 1073741824;
        }
        if (fileSize > size) {
            return false;
        }
        return true;
    }

}
